home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 301-325 / disk_313 / uucp / uucp1.lzh / src / News060 / rnews.c < prev   
C/C++ Source or Header  |  1990-01-10  |  17KB  |  773 lines

  1.  
  2. /*
  3.  *  RNEWS.C
  4.  *
  5.  *  Copyright 1988 by William Loftus.  All rights reserved.
  6.  *  (C) Copyright 1989-1990 by Matthew Dillon,  All Rights Reserved.
  7.  *
  8.  *  Version 0.60 Beta
  9.  *
  10.  *  This is rnews for compressed news.    News 2.11 will uux
  11.  *  a file to this system that will be in compressed format.
  12.  *  This program will strip off the "#! cunbatch", uncompress
  13.  *  the news, and call unbatch.  If the news is not in compressed
  14.  *  format it will just pass it to unbatch.
  15.  */
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <log.h>
  21. #include "/version.h"
  22. #include <errno.h>
  23. #include <ctype.h>
  24.  
  25. #define MAXGROUPS   1024
  26.  
  27. IDENT(".01");
  28.  
  29. void uncompress_news();
  30. void unbatch_news();
  31. void writeerr();
  32. void CreateDirsFor();
  33. char *TmpFileName();
  34.  
  35. int    Compressed;
  36. char    *SeqFile = "UULIB:SeqNews";
  37. char    *TmpFile;
  38.  
  39. void
  40. main (argc, argv)
  41. int argc;
  42. char **argv;
  43. {
  44.     FILE *fp;
  45.     char buf[32];
  46.     int ch;
  47.     int status = 0;
  48.  
  49.     LogProgram = "RNews";
  50.     TmpFile = TmpFileName("T:mail");
  51.  
  52.     fclose(stderr);  /* Assume we are running in the background */
  53.  
  54.     fgets(buf, 13, stdin);
  55.  
  56.     if (!strncmp(buf,"#! cunbatch", 11)) {
  57.     Compressed = 1;
  58.     } else if (!strncmp(buf,"#! rnews", 8)) {
  59.     fp = fopen(TmpFile, "w");
  60.     if (fp == (char *)NULL) {
  61.         ulog(-1, "Unable to open %s for output", TmpFile);
  62.         exit(1);
  63.     }
  64.     fprintf(fp, "%s\n",  buf);
  65.     while ((ch = getchar()) != EOF) {
  66.         fputc(ch, fp);
  67.     }
  68.     fclose(fp);
  69.     Compressed = 0;
  70.     } else {
  71.     ulog(-1, "News in wrong format");
  72.     remove(TmpFile);
  73.     exit(1);
  74.     }
  75.  
  76.     if (Compressed) {
  77.     uncompress_news();
  78.     }
  79.  
  80.     unbatch_news();
  81.  
  82.     status = remove(TmpFile);
  83.  
  84.     if (status != 0) {
  85.     ulog(-1, "Unable to remove %s", TmpFile);
  86.     exit(1);
  87.     }
  88. }
  89.  
  90. /*
  91.  * Unbatch, an Amiga unbatcher.
  92.  *
  93.  *  Written by Fred Cassirer, 10/8/88.
  94.  *  Some unbatch code originally taken from News2.11 sources.
  95.  *
  96.  *  Ported to Lattice 5.0
  97.  *  Added config.h file
  98.  *  Added use of ERRORFILE
  99.  *  11/23/1988    Dan 'Sneakers' Schein
  100.  *
  101.  * This code (as well as the unbatch stuff) is free for anyone who thinks
  102.  * they can get some use out of it.
  103.  *
  104.  *  Articles will only
  105.  *  be placed in newsgroups as defined in the "UULIB:NewsGroups"
  106.  *  control file.  Articles which are not listed in the control file
  107.  *  are placed in the "Reject" directory.  Articles are sequenced by
  108.  *  the sequencer in "UULIB:seqnews". This could possibly be updated
  109.  *  to use a sequencer within each of the subdirectories, to more closely
  110.  *  resemble the News system under Unix.
  111.  *
  112.  *  Unbatch will also take command line args of files to be unbatched.
  113.  *  Files on the command line are not removed, they should be removed
  114.  *  after running unbatch.
  115.  */
  116.  
  117. static char *groups[MAXGROUPS];
  118.  
  119. void
  120. unbatch_news()
  121. {
  122.     if (!freopen(TmpFile, "r", stdin)) {
  123.     ulog(-1, "Can't unbatch, expected file %s to exist", TmpFile);
  124.     exit(1);
  125.     }
  126.     if (unbatch())
  127.     ulog(-1, "Unbatch failed");
  128.     fclose(stdin);
  129. }
  130.  
  131.  
  132. void
  133. initgroups(newsgroups)
  134. char *newsgroups;
  135. {
  136.     static char buf[BUFSIZ];
  137.     static int initflag = 0;
  138.     int i, len;
  139.     FILE *fp;
  140.  
  141.     if (initflag)
  142.     return;
  143.  
  144.     initflag = 1;
  145.  
  146.     if ((fp = fopen(newsgroups, "r")) == NULL)  {
  147.     ulog(-1, "Unable to open newsgroup file %s", newsgroups);
  148.     remove(TmpFile);
  149.     exit(2);
  150.     }
  151.  
  152.     i = 0;
  153.     while (fgets(buf, BUFSIZ, fp) && (i < MAXGROUPS)) {
  154.     len = strlen(buf) - 1;
  155.     buf[len] = '\0';
  156.     if ((groups[i] = malloc(len+1)) == NULL) {
  157.         ulog(-1, "malloc failed");
  158.         remove(TmpFile);
  159.         exit(4);
  160.     }
  161.     strcpy(groups[i], buf);
  162.     i++;
  163.     }
  164.     groups[i] = NULL;
  165.     fclose(fp);
  166. }
  167.  
  168. char *
  169. finddir(dir)
  170. char *dir;
  171. {
  172.     static char work[40];
  173.     char *p;
  174.     int i;
  175.  
  176.     while (1) {
  177.     p = work;
  178.     while ((*dir != ' ') && (*dir != ',') && *dir)
  179.         *p++ = *dir++;
  180.  
  181.     *p = '\0';
  182.     for (i = 0; groups[i] != NULL; ++i) {
  183.         if (strcmpi(groups[i], work) == 0)
  184.         return(work);
  185.     }
  186.  
  187.     if (!*dir++)
  188.         break;
  189.     }
  190.     return(NULL);
  191. }
  192.  
  193. /*
  194.  * unbatchnews: extract news in batched format and process it one article
  195.  * at a time.  The format looks like
  196.  *    #! rnews 1234
  197.  *    article containing 1234 characters
  198.  *    #! rnews 4321
  199.  *    article containing 4321 characters
  200.  *
  201.  *    or
  202.  *
  203.  *    #! command [args]
  204.  *    calls LIBDIR/command [args] to process the news
  205.  */
  206.  
  207. #define MAXARGS     20
  208. #define FILES_PER_LINE    5
  209.  
  210. char buf[BUFSIZ];
  211. char homedir[128];
  212.  
  213. unbatch()
  214. {
  215.     int c;
  216.     FILE *pfn;
  217.     long size;
  218.     FILE *seq;
  219.     char filename[128], tmpname[30];
  220.     int  seqno, fcount;
  221.     long atol();
  222.     char *dir;
  223.  
  224.     initgroups("UULIB:Newsgroups");
  225.  
  226.     if ((seq = fopen(SeqFile, "r")) != NULL) {
  227.     fscanf(seq,"%d",&seqno);
  228.     fclose(seq);
  229.     } else {
  230.     ulog(-1, "Sequence file %s not found, creating", SeqFile);
  231.     seqno = 0;
  232.     }
  233.  
  234.     if (gets(buf) == NULL) {
  235.     ulog(-1, "Empty file!");
  236.     return(2);
  237.     }
  238.  
  239.     if (strncmp(buf, "#! rnews ", 9) != 0) {
  240.     ulog(-1, "unbatch: rnews cmd not supported '%s'!", buf);
  241.     return(1);
  242.     }
  243.  
  244.     fcount = 0;
  245.     do {
  246.     if (!fcount) {
  247.         fflush(stdout);
  248.         fcount = FILES_PER_LINE;
  249.     }
  250.     while (strncmp(buf, "#! rnews ", 9) && strncmp(buf, "! rnews ", 8)) { /* kludge for bug */
  251.         char *cp;
  252.         for (cp = buf; *cp != '\0'; ++cp) {
  253.         if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp)))
  254.             *cp = '?';
  255.         }
  256.         ulog(-1, "out of sync, skipping %s", buf);
  257.         if (gets(buf) == NULL)
  258.         return(0);
  259.     }
  260.  
  261.     size = atol(buf + (buf[0] == '#' ? 9 : 8));
  262.     if (size <= 0) {
  263.         ulog(-1, "nonsense size %ld", size);
  264.         continue;
  265.     }
  266.  
  267.     sprintf(tmpname,"UUNEWS:Tmp%d", ++seqno);
  268.     fcount--;
  269.     fflush(stdout);
  270.     if ((pfn = fopen(tmpname, "w")) == NULL) {
  271.         ulog(-1, "Can't create %s", tmpname);
  272.         exit(3);
  273.     }
  274.  
  275.     while (gets(buf)) {
  276.         fprintf(pfn, "%s\n", buf);
  277.         size -= strlen(buf) + 1;
  278.         if (strncmp(buf, "Newsgroup", 9) == 0) {
  279.         if (!(dir = finddir(buf+12))) {
  280.             ulog(-1, "Articles for %s placed in Rejects", buf+12);
  281.             dir = "Rejects";
  282.         }
  283.         sprintf(filename, "UUNEWS:%s/%d", dir, seqno);
  284.         break; /* Get out of the while */
  285.         }
  286.     }
  287.  
  288.     if (size > 0) {
  289.         while(--size >= 0 && (c = getc(stdin)) != EOF)
  290.         putc(c, pfn);
  291.         if (ferror(pfn) || fclose(pfn)) {   /* disk full? */
  292.         ulog(-1, "Error writing to temp file");
  293.         break;
  294.         }
  295.         if (rename(tmpname, filename) < 0) {
  296.         CreateDirsFor(filename);
  297.         rename(tmpname, filename);
  298.         }
  299.     }
  300.  
  301.        /*
  302.     * If we got a truncated batch, don't process the
  303.     * last article; it will probably be received again.
  304.     */
  305.  
  306.     if (size > 0) {
  307.         ulog(-1, "truncated batch");
  308.         break;
  309.     }
  310.     } while (gets(buf) != NULL);
  311.  
  312.     if ((seq = fopen(SeqFile, "w")) == NULL) {
  313.     ulog(-1, "Unable to create %s", SeqFile);
  314.     }
  315.     fprintf(seq, "%d\n", seqno);
  316.     fclose(seq);
  317.     return(0);
  318. }
  319.  
  320. int
  321. System(cmd)
  322. char *cmd;
  323. {
  324.     long nl;
  325.     int return_value;
  326.  
  327.     if ((nl = (long)Open("null:wpl", 1006)) != NULL) {
  328.     return_value = (Execute(cmd, nl, nl) == -1) ? 0 : -1;
  329.     Close(nl);
  330.     } else {
  331.     ulog(-1, "Unable to open NULL: device, did you mount it?");
  332.     return_value = -1;
  333.     }
  334.     return return_value;
  335. }
  336.  
  337.  
  338. /*
  339.  * Set USERMEM to the maximum amount of physical user memory available
  340.  * in bytes.  USERMEM is used to determine the maximum BITS that can be used
  341.  * for compression.
  342.  *
  343.  * SACREDMEM is the amount of physical memory saved for others; compress
  344.  * will hog the rest.
  345.  */
  346. #ifndef SACREDMEM
  347. #define SACREDMEM    0
  348. #endif
  349.  
  350. #ifndef USERMEM
  351. /*# ifdef AMIGA
  352. #   define USERMEM    200000
  353. # else*/
  354. #   define USERMEM    450000    /* default user memory */
  355. /* # endif*/
  356. #endif
  357.  
  358. #ifdef interdata        /* (Perkin-Elmer) */
  359. #define SIGNED_COMPARE_SLOW    /* signed compare is slower than unsigned */
  360. #endif
  361.  
  362. #ifdef pdp11
  363. # define BITS    12    /* max bits/code for 16-bit machine */
  364. # define NO_UCHAR    /* also if "unsigned char" functions as signed char */
  365. # undef USERMEM
  366. #endif /* pdp11 */    /* don't forget to compile with -i */
  367.  
  368. #ifdef z8000
  369. # define BITS    12
  370. # undef vax        /* weird preprocessor */
  371. # undef USERMEM
  372. #endif /* z8000 */
  373.  
  374. #ifdef pcxt
  375. # define BITS    12
  376. # undef USERMEM
  377. #endif /* pcxt */
  378.  
  379. #ifdef USERMEM
  380. # if USERMEM >= (433484+SACREDMEM)
  381. #  define PBITS 16
  382. # else
  383. #  if USERMEM >= (229600+SACREDMEM)
  384. #   define PBITS    15
  385. #  else
  386. #   if USERMEM >= (127536+SACREDMEM)
  387. #    define PBITS    14
  388. #   else
  389. #    if USERMEM >= (73464+SACREDMEM)
  390. #     define PBITS    13
  391. #    else
  392. #     define PBITS    12
  393. #    endif
  394. #   endif
  395. #  endif
  396. # endif
  397. # undef USERMEM
  398. #endif /* USERMEM */
  399.  
  400. #ifdef PBITS        /* Preferred BITS for this memory size */
  401. # ifndef BITS
  402. #  define BITS PBITS
  403. # endif BITS
  404. #endif /* PBITS */
  405.  
  406. #if BITS == 16
  407. # define HSIZE    69001        /* 95% occupancy */
  408. #endif
  409. #if BITS == 15
  410. # define HSIZE    35023        /* 94% occupancy */
  411. #endif
  412. #if BITS == 14
  413. # define HSIZE    18013        /* 91% occupancy */
  414. #endif
  415. #if BITS == 13
  416. # define HSIZE    9001        /* 91% occupancy */
  417. #endif
  418. #if BITS <= 12
  419. # define HSIZE    5003        /* 80% occupancy */
  420. #endif
  421.  
  422. #ifdef M_XENIX            /* Stupid compiler can't handle arrays with */
  423. # if BITS == 16         /* more than 65535 bytes - so we fake it */
  424. #  define XENIX_16
  425. # else
  426. #  if BITS > 13         /* Code only handles BITS = 12, 13, or 16 */
  427. #   define BITS 13
  428. #  endif
  429. # endif
  430. #endif
  431.  
  432. /*
  433.  * a code_int must be able to hold 2**BITS values of type int, and also -1
  434.  */
  435. #if BITS > 15
  436. typedef long int    code_int;
  437. #else
  438. typedef int        code_int;
  439. #endif
  440.  
  441. #ifdef SIGNED_COMPARE_SLOW
  442. typedef unsigned long int count_int;
  443. typedef unsigned short int count_short;
  444. #else
  445. typedef long int      count_int;
  446. #endif
  447.  
  448. #ifdef NO_UCHAR
  449.  typedef char    char_type;
  450. #else
  451.  typedef    unsigned char    char_type;
  452. #endif /* UCHAR */
  453. char_type magic_header[] = { "\037\235" };      /* 1F 9D */
  454.  
  455. /* Defines for third byte of header */
  456. #define BIT_MASK    0x1f
  457. #define BLOCK_MASK    0x80
  458. /* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
  459.    a fourth header byte (for expansion).
  460. */
  461. #define INIT_BITS 9            /* initial number of bits/code */
  462.  
  463. #include <stdio.h>
  464. #include <ctype.h>
  465.  
  466. int n_bits;                /* number of bits/code */
  467. int maxbits = BITS;            /* user settable max # bits/code */
  468. code_int maxcode;            /* maximum code, given n_bits */
  469. code_int maxmaxcode = 1 << BITS;    /* should NEVER generate this code */
  470. #define MAXCODE(n_bits)        ((1 << (n_bits)) - 1)
  471.  
  472. count_int htab [HSIZE];
  473. unsigned short codetab [HSIZE];
  474. #define htabof(i)       htab[i]
  475. #define codetabof(i)    codetab[i]
  476. code_int hsize = HSIZE;         /* for dynamic table sizing */
  477. count_int fsize;
  478.  
  479. /*
  480.  * To save much memory, we overlay the table used by compress() with those
  481.  * used by decompress().  The tab_prefix table is the same size and type
  482.  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
  483.  * get this from the beginning of htab.  The output stack uses the rest
  484.  * of htab, and contains characters.  There is plenty of room for any
  485.  * possible stack (stack used to be 8000 characters).
  486.  */
  487.  
  488. #define tab_prefixof(i) codetabof(i)
  489. #define tab_suffixof(i)        (((char_type *)htab)[i])
  490. #define tab_suffixof1(i)        (((long)htab)+(long)(i))
  491. #define de_stack           (char_type *)(tab_suffixof1(1<<BITS))
  492.  
  493. code_int free_ent = 0;            /* first unused entry */
  494. int exit_stat = 0;
  495.  
  496. code_int getcode();
  497.  
  498. void _fprintf() { }
  499.  
  500. int nomagic = 0;    /* Use a 3-byte magic number header, unless old file */
  501.  
  502. /*
  503.  * block compression parameters -- after all codes are used up,
  504.  * and compression rate changes, start over.
  505.  */
  506. int block_compress = BLOCK_MASK;
  507. int clear_flg = 0;
  508. long int ratio = 0;
  509. #define CHECK_GAP 10000 /* ratio check interval */
  510. count_int checkpoint = CHECK_GAP;
  511. /*
  512.  * the next two codes should not be changed lightly, as they must not
  513.  * lie within the contiguous general code space.
  514.  */
  515. #define FIRST    257    /* first free entry */
  516. #define CLEAR    256    /* table clear output code */
  517.  
  518. int (*bgnd_flag)();
  519.  
  520. static void decompress ();
  521. static void compress ();
  522.  
  523. void
  524. uncompress_news()
  525. {
  526.     if (freopen(TmpFile, "w", stdout) == NULL) {
  527.        ulog(-1, "Can't open uncompressed file %s", TmpFile);
  528.        exit(1);
  529.     }
  530.  
  531.     maxbits = BITS;
  532.     maxmaxcode = 1 << maxbits;
  533.  
  534.     /* Check the magic number */
  535.     if (nomagic == 0) {
  536.        if ((getchar()!=(magic_header[0] & 0xFF))
  537.       || (getchar()!=(magic_header[1] & 0xFF))) {
  538.         ulog(-1, "stdin: not in compressed format");
  539.         exit(1);
  540.     }
  541.     maxbits = getchar();    /* set -b from file */
  542.     block_compress = maxbits & BLOCK_MASK;
  543.     maxbits &= BIT_MASK;
  544.     maxmaxcode = 1 << maxbits;
  545.     fsize = 100000;     /* assume stdin large for USERMEM */
  546.     }
  547.   decompress();
  548.  
  549.   fclose(stdout);
  550. }
  551.  
  552. static int offset;
  553. long int in_count = 1;            /* length of input */
  554. long int bytes_out;            /* length of compressed output */
  555. long int out_count = 0;         /* # of codes output (for debugging) */
  556.  
  557.  
  558. /*
  559.  * Decompress stdin to stdout.    This routine adapts to the codes in the
  560.  * file building the "string" table on-the-fly; requiring no table to
  561.  * be stored in the compressed file.  The tables used herein are shared
  562.  * with those of the compress() routine.  See the definitions above.
  563.  */
  564.  
  565. static void decompress() {
  566.     register char_type *stackp;
  567.     register int finchar;
  568.     register code_int code, oldcode, incode;
  569.  
  570.     /*
  571.      * As above, initialize the first 256 entries in the table.
  572.      */
  573.     maxcode = MAXCODE(n_bits = INIT_BITS);
  574.     for ( code = 255; code >= 0; code-- ) {
  575.     tab_prefixof(code) = 0;
  576.     tab_suffixof(code) = (char_type)code;
  577.     }
  578.     free_ent = ((block_compress) ? FIRST : 256 );
  579.  
  580.     finchar = oldcode = getcode();
  581.     if(oldcode == -1)   /* EOF already? */
  582.     return;         /* Get out of here */
  583.     putchar( (char)finchar );   /* first code must be 8 bits = char */
  584.     if(ferror(stdout))          /* Crash if can't write */
  585.     writeerr();
  586.     stackp = de_stack;
  587.  
  588.     while ( (code = getcode()) > -1 ) {
  589.  
  590.     if ( (code == CLEAR) && block_compress ) {
  591.         for ( code = 255; code >= 0; code-- )
  592.         tab_prefixof(code) = 0;
  593.         clear_flg = 1;
  594.         free_ent = FIRST - 1;
  595.         if ( (code = getcode ()) == -1 )    /* O, untimely death! */
  596.         break;
  597.     }
  598.     incode = code;
  599.     /*
  600.      * Special case for KwKwK string.
  601.      */
  602.     if ( code >= free_ent ) {
  603.         *stackp++ = finchar;
  604.         code = oldcode;
  605.     }
  606.  
  607.     /*
  608.      * Generate output characters in reverse order
  609.      */
  610. #ifdef SIGNED_COMPARE_SLOW
  611.     while ( ((unsigned long)code) >= ((unsigned long)256) ) {
  612. #else
  613.     while ( code >= 256 ) {
  614. #endif
  615.         *stackp++ = tab_suffixof(code);
  616.         code = tab_prefixof(code);
  617.     }
  618.     *stackp++ = finchar = tab_suffixof(code);
  619.  
  620.     /*
  621.      * And put them out in forward order
  622.      */
  623.     do
  624.         putchar ( *--stackp );
  625.     while ( stackp > de_stack );
  626.  
  627.     /*
  628.      * Generate the new entry.
  629.      */
  630.     if ( (code=free_ent) < maxmaxcode ) {
  631.         tab_prefixof(code) = (unsigned short)oldcode;
  632.         tab_suffixof(code) = finchar;
  633.         free_ent = code+1;
  634.     }
  635.     /*
  636.      * Remember previous code.
  637.      */
  638.     oldcode = incode;
  639.     }
  640.  
  641.     fflush( stdout );
  642.     if(ferror(stdout))
  643.     writeerr();
  644. }
  645.  
  646. char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
  647. char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  648.  
  649. /*****************************************************************
  650.  * TAG( getcode )
  651.  *
  652.  * Read one code from the standard input.  If EOF, return -1.
  653.  * Inputs:
  654.  *    stdin
  655.  * Outputs:
  656.  *    code or -1 is returned.
  657.  */
  658.  
  659. code_int
  660. getcode() {
  661.     /*
  662.      * On the VAX, it is important to have the register declarations
  663.      * in exactly the order given, or the asm will break.
  664.      */
  665.     register code_int code;
  666.     static int offset = 0, size = 0;
  667.     static char_type buf[BITS];
  668.     register int r_off, bits;
  669.     register char_type *bp = buf;
  670.  
  671.     if ( clear_flg > 0 || offset >= size || free_ent > maxcode ) {
  672.     /*
  673.      * If the next entry will be too big for the current code
  674.      * size, then we must increase the size.  This implies reading
  675.      * a new buffer full, too.
  676.      */
  677.     if ( free_ent > maxcode ) {
  678.         n_bits++;
  679.         if ( n_bits == maxbits )
  680.         maxcode = maxmaxcode;    /* won't get any bigger now */
  681.         else
  682.         maxcode = MAXCODE(n_bits);
  683.     }
  684.     if ( clear_flg > 0) {
  685.         maxcode = MAXCODE (n_bits = INIT_BITS);
  686.         clear_flg = 0;
  687.     }
  688.     size = fread( buf, 1, n_bits, stdin );
  689.     if ( size <= 0 )
  690.         return -1;            /* end of file */
  691.     offset = 0;
  692.     /* Round size down to integral number of codes */
  693.     size = (size << 3) - (n_bits - 1);
  694.     }
  695.     r_off = offset;
  696.     bits = n_bits;
  697.     /*
  698.      * Get to the first byte.
  699.      */
  700.     bp += (r_off >> 3);
  701.     r_off &= 7;
  702.     /* Get first part (low order bits) */
  703. #ifdef NO_UCHAR
  704.     code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
  705. #else
  706.     code = (*bp++ >> r_off);
  707. #endif /* NO_UCHAR */
  708.     bits -= (8 - r_off);
  709.     r_off = 8 - r_off;        /* now, offset into code word */
  710.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  711.     if ( bits >= 8 ) {
  712. #ifdef NO_UCHAR
  713.         code |= (*bp++ & 0xff) << r_off;
  714. #else
  715.         code |= *bp++ << r_off;
  716. #endif /* NO_UCHAR */
  717.         r_off += 8;
  718.         bits -= 8;
  719.     }
  720.     /* high order bits. */
  721.     code |= (*bp & rmask[bits]) << r_off;
  722.     offset += n_bits;
  723.  
  724.     return code;
  725. }
  726.  
  727. char *
  728. rindex(s, c)            /* For those who don't have it in libc.a */
  729. char *s, c;
  730. {
  731.     char *p;
  732.     for (p = NULL; *s; s++)
  733.     if (*s == c)
  734.         p = s;
  735.     return(p);
  736. }
  737.  
  738. void
  739. writeerr()
  740. {
  741.     perror ( TmpFile );
  742.     unlink ( TmpFile );
  743.     exit ( 1 );
  744. }
  745.  
  746. /*
  747.  *  assign:path/path/path.../filename
  748.  *
  749.  *  creates path directories
  750.  */
  751.  
  752. void
  753. CreateDirsFor(filename)
  754. char *filename;
  755. {
  756.     short i;
  757.     short j;
  758.  
  759.     for (i = 0; ; ++i) {
  760.     for (j = i; filename[j] && filename[j] != ':' && filename[j] != '/'; ++j);
  761.     if (filename[j] == 0)
  762.         break;
  763.     if (filename[j] == ':') {
  764.         i = j;
  765.         continue;
  766.     }
  767.     filename[j] = 0;
  768.     mkdir(filename);        /*  may fail if parents already exist */
  769.     filename[j] = '/';
  770.     }
  771. }
  772.  
  773.